﻿using LightCAD.Core;
using LightCAD.Drawing;
using LightCAD.Drawing.Actions;
using LightCAD.Runtime;
using SkiaSharp;
using System.Linq;
using System.Collections.Generic;
using LightCAD.Three;
using LightCAD.Three.OpenGL;
using LightCAD.MathLib;

namespace QdWater
{
    public class PipeAction : ElementAction
    {
        public PipeAction() { }

        public PipeAction(IDocumentEditor docEditor)
         : base(docEditor)
        {
            this.commandCtrl.WriteInfo("命令：Line");
        }
        static PipeAction()
        {
            CreateMethods = new LcCreateMethod[1];
            CreateMethods[0] = new LcCreateMethod()
            {
                Name = "CreatePipe",
                Description = "创建水管",
                Steps = new LcCreateStep[]
                {
                    new LcCreateStep { Name = "Step0", Options = "指定第一个点:" },
                    new LcCreateStep { Name = "Step1", Options = "管道下一点或 回退(U)]<另一段>:" },
                    new LcCreateStep { Name = "Step2", Options = "指定下一个点或[放弃(U)]:" },
                }
            };
        }
        internal static void Initilize()
        {
            WaterActions.PipeAction = new PipeAction();
            LcDocument.ElementActions.Add(WaterElementType.Pipe, WaterActions.PipeAction);
        }
        private static readonly LcCreateMethod[] CreateMethods;
        private List<Vector2> points;
        private Vector2 firstPoint { get; set; }
        private Line2d? lastLine { get; set; }
        private double pipeWidth = 100;

        private Vector2 secondPoint { get; set; }
        private PointInputer inputer { get; set; }

        public async void ExecCreate(string[] args = null)
        {

            this.points = new List<Vector2>();
            this.StartCreating();
            this.inputer = new PointInputer(this.docEditor);
            var curMethod = CreateMethods[0];

        Step0:
            var step0 = curMethod.Steps[0];
            var result0 = await inputer.Execute(step0.Options);
            //var result0 = await inputer.Execute(step0.Options);

            if (inputer.isCancelled)
            {
                this.Cancel();
                goto End;
            }

            // zcb: 增加Res0为空的判定
            if (result0 == null)
            {
                this.Cancel();
                goto End;
            }

            if (result0.ValueX == null)
            {
                if (result0.Option != null)
                {
                    goto Step0;
                    //TODO:AutoCAD画线输入一个数字，是怎么确定点的？
                }
                else
                {
                    goto Step0;
                }
            }

            this.firstPoint = (Vector2)result0.ValueX;

        Step1:
            var step1 = curMethod.Steps[1];
            if (this.points.Count >= 2)
            {
                step1 = curMethod.Steps[2];
            }

            var result1 = await inputer.Execute(step1.Options);
            if (inputer.isCancelled)
            {
                this.Cancel();
                goto End;
            }



            if (result1.Option != null)
            {
                if (result1.Option == "U") { }
                else if (result1.Option == "C")
                {
                    goto End;
                }
                else if (result1.Option == " ")
                {
                    goto End;
                }
                else if (result1.ValueX != null)
                {
                    Vector2 pointB = (Vector2)result1.ValueX;
                    Vector2 direction = (pointB - firstPoint).Normalize();
                    result1.ValueX = firstPoint + direction * double.Parse(result1.Option);
                    //TODO:AutoCAD画线输入一个数字，是怎么确定点的？
                }
                else
                {
                    goto Step1;
                }
            }

            this.secondPoint = (Vector2)result1.ValueX;

            CreatePipe(firstPoint, secondPoint, ComponentManager.GetCptDef<LcPipeDef>(PipeAttribute.CommonWallUuid));
            firstPoint = secondPoint;
            goto Step1;

        End:
            this.inputer = null;
            this.EndCreating();
        }
        private bool CreatePipe(Vector2 sp, Vector2 ep, LcPipeDef lcPipeDef, double width = 200)
        {
            Line2d line2D = new Line2d();
            line2D.Start = sp;
            line2D.End = ep;
            var doc = this.docRt.Document;
            var lcPipe = new LcPipe(lcPipeDef);
            lcPipe.Initilize(doc);
            lcPipe.BaseCurve = line2D;
            // wall.Curves[0].Curve2ds.Add(line2D);
            lcPipe.Width = width;
            lcPipe.Bottom = 0;
            WaterConnector startConnector = new WaterConnector();
            startConnector.CenterPoint = sp;
            lcPipe.Connectors.Add(0, startConnector);
            WaterConnector endConnector = new WaterConnector();
            endConnector.CenterPoint = ep;
            lcPipe.Connectors.Add((int)line2D.Length, endConnector);
            DisposePipes(lcPipe);

            this.docRt.Action.ClearSelects();
            return true;
        }




        public override void DrawTemp(SKCanvas canvas)
        {
            if (this.firstPoint == null)
            {
                return;
            }

            var mp = this.vportRt.PointerMovedPosition.ToVector2d();
            var wcs_mp = this.vportRt.ConvertScrToWcs(mp);
            var sk_p = this.vportRt.ConvertWcsToScr(wcs_mp).ToSKPoint();
            var start = this.vportRt.ConvertWcsToScr(this.firstPoint).ToSKPoint();
            using (var elePen = new SKPaint { Color = SKColors.Yellow, IsStroke = true, PathEffect = SKPathEffect.CreateDash(new float[] { 10, 10, 30, 10 }, 0) })
            {
                canvas.DrawLine(start, sk_p, elePen);
            }
            Line2d baseline = new Line2d();
            baseline.Start = this.firstPoint;
            baseline.End = wcs_mp;
        }

        public override void Draw(SKCanvas canvas, LcElement element, Vector2 offset)
        {
            Matrix3 matrix = Matrix3.GetTranslate(offset);
            var lcPipe = element as LcPipe;
            foreach (var line in lcPipe.GetBaseLines())
            {
                var mstart = matrix.MultiplyPoint(line.Start);
                var mend = matrix.MultiplyPoint(line.End);
                var start = this.vportRt.ConvertWcsToScr(mstart).ToSKPoint();
                var end = this.vportRt.ConvertWcsToScr(mend).ToSKPoint();

                using (var elePen = new SKPaint { Color = new SKColor(element.GetColorValue()), IsStroke = true })
                {
                    canvas.DrawLine(start, end, elePen);
                }
            }
        }

        public override ControlGrip[] GetControlGrips(LcElement element)
        {
            var group = element as LcPipe;
            var grips = new List<ControlGrip>();
            foreach (WaterConnector connector in group.Connectors.Values)
            {

                var gripCenter = new ControlGrip
                {
                    Element = group,
                    Name = "Connector",
                    Position = connector.CenterPoint,

                };
                grips.Add(gripCenter);
            }


            return grips.ToArray();
        }

        private string _gripName;
        private Vector2 _position;
        private Vector2 _endDrag;
        private LcPipe _pipe;
        private List<LcPipe> _pipes;
        public override void DrawDragGrip(SKCanvas canvas)
        {

            //if (_pipe == null) return;
            //if (_gripName == "Center")
            //{
            //    Matrix3 matrix3d = Matrix3.GetMove(_pipe.BoundingBox.Center, _position);
            //    Line2d line = new Line2d();
            //    line.Start = matrix3d.MultiplyPoint(_pipe.BaseLine.Start);
            //    line.End = matrix3d.MultiplyPoint(_pipe.BaseLine.End);
            //    Draw(canvas, line);
            //}
            //else
            //{
            //    Line2d line = new Line2d();
            //    _pipes = new List<LcPipe>();
            //    line = new Line2d();
            //    Vector2 po;
            //    if (_gripName == "Start")
            //    {
            //        line.Start = _position;
            //        line.End = _pipe.BaseLine.End;
            //        po = _pipe.BaseLine.Start;
            //    }
            //    else
            //    {
            //        line.Start = _pipe.BaseLine.Start;
            //        line.End = _position;
            //        po = _pipe.BaseLine.End;
            //    }
            //    Draw(canvas, line);
            //    foreach (ControlGrip item in this.vportRt.ElementGrips)
            //    {
            //        if (item.Position.Similarity(po))
            //        {
            //            LcPipe p = item.Element as LcPipe;
            //            if (p != _pipe)
            //            {

            //                if (item.Name == "Start")
            //                {
            //                    line = new Line2d();
            //                    line.Start = _position;
            //                    line.End = p.BaseLine.End;
            //                    Draw(canvas, line);
            //                }
            //                else
            //                    if (item.Name == "End")
            //                {
            //                    line = new Line2d();
            //                    line.Start = p.BaseLine.Start;
            //                    line.End = _position;
            //                    Draw(canvas, line);
            //                }
            //            }
            //        }
            //    }

            //}
        }

        public override void SetDragGrip(LcElement element, string gripName, Vector2 position, bool isEnd)
        {
            _pipe = element as LcPipe;

            if (!isEnd)
            {
                _gripName = gripName;
                _position = position;
            }
            else
            {
                Vector2 start = _pipe.Connectors[0].CenterPoint;
                Vector2 end = _pipe.Connectors[1].CenterPoint;
                if (gripName == "Center")
                {
                    Matrix3 matrix3d = Matrix3.GetMove(_pipe.BoundingBox.Center, _position);
                    Line2d line = new Line2d();

                    line.Start = matrix3d.MultiplyPoint(start);
                    line.End = matrix3d.MultiplyPoint(end);

                    _pipe.OnPropertyChangedBefore(nameof(_pipe.BaseCurve), _pipe.BaseCurve, _pipe.BaseCurve);
                    _pipe.BaseCurve = line;
                    _pipe.ResetCache();
                    _pipe.OnPropertyChangedAfter(nameof(_pipe.BaseCurve), _pipe.BaseCurve, _pipe.BaseCurve);
                }
                else
                {
                    Line2d line = new Line2d();
                    if (_gripName == "Start")
                    {
                        line.Start = _position;
                        line.End = end;
                    }
                    else
                    {
                        line.Start = start;
                        line.End = _position;
                    }

                    _pipe.OnPropertyChangedBefore(nameof(_pipe.BaseCurve), _pipe.BaseCurve, _pipe.BaseCurve);
                    _pipe.BaseCurve = line;
                    _pipe.ResetCache();
                    _pipe.OnPropertyChangedAfter(nameof(_pipe.BaseCurve), _pipe.BaseCurve, _pipe.BaseCurve);
                }
            }
        }

        private void DisposePipes(LcPipe lcPipe)
        {
            List<LcPipe> pipes = new List<LcPipe>();
            foreach (var ele in this.docRt.Document.ModelSpace.Elements)
            {
                if (ele.BoundingBox == null)
                {
                    continue;
                }
                if (ele.BoundingBox.IntersectsBox(lcPipe.BoundingBox))
                {
                    if (ele is LcPipe)
                    {
                        pipes.Add(ele as LcPipe);
                    }
                }
            }
            foreach (var lineA in lcPipe.GetBaseLines())
            {
                foreach (var pipe in pipes)
                {
                    foreach (var lineB in pipe.GetBaseLines())
                    {
                        Vector2 vector2 = Line2d.GetCrossVector(lineA, lineB);
                        if (vector2 != null)
                        {
                            WaterConnector waterConnector = new WaterConnector();
                            waterConnector.CenterPoint = vector2;
                            var disA = (int)vector2.DistanceTo(lcPipe.Connectors[0].CenterPoint);
                            var disB= (int)vector2.DistanceTo(pipe.Connectors[0].CenterPoint);
                            int len = 100;
                            lcPipe.Connectors.Add(disA- len, waterConnector);
                            lcPipe.Connectors.Add(disA+ len, waterConnector);
                            pipe.Connectors.Add(disB - len, waterConnector);
                            pipe.Connectors.Add(disB + len, waterConnector);
                            break;
                        }
                    }
                }
            }

            this.docRt.Document.ModelSpace.InsertElement(lcPipe);
            return;

        }


    }
}